package cn.zswltech.gruul.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.zswltech.gruul.biz.service.FunctionService;
import cn.zswltech.gruul.biz.support.impl.IServiceImpl;
import cn.zswltech.gruul.common.constant.MenuConstants;
import cn.zswltech.gruul.common.dal.dao.*;
import cn.zswltech.gruul.common.dto.*;
import cn.zswltech.gruul.common.entity.*;
import cn.zswltech.gruul.common.result.MSG;
import cn.zswltech.gruul.common.result.Response;
import cn.zswltech.gruul.web.api.util.AccountUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.util.Sqls;
import java.util.Date;
import java.util.List;
import java.util.Map;


@Service("functionService")
public class FunctionServiceImpl extends IServiceImpl<FunctionDO> implements FunctionService {
    private final static Logger logger = LoggerFactory.getLogger(FunctionServiceImpl.class);
    @Autowired
    private FunctionDOMapper functionDOMapper;
    @Autowired
    private MenuDOMapper menuDOMapper;
    @Autowired
    private RoleMenuFunctionDOMapper roleMenuFunctionDOMapper;
    @Autowired
    private OrgMenuFunctionDOMapper orgMenuFunctionDOMapper;


    @Override
    public FunctionDO queryById(Long id) {
        FunctionDO functionDO = null;
        try {
            if (id == null) {
                return functionDO;
            }
            FunctionDO query = new FunctionDO();
            query.setId(id);
            functionDO = functionDOMapper.selectOne(query);
        } catch (Exception e) {
            logger.error("queryById error", e);
        }
        return functionDO;
    }

    @Override
    public Response<List<FunctionDO>> queryByMenuId(Long menuId) {
        Response<List<FunctionDO>> response = new Response<List<FunctionDO>>();
        try {
            if (menuId == null) {
                response.setMessage(MSG.req_error_param_null, "menuId");
                return response;
            }
            List<FunctionDO> functionDOs = functionDOMapper.queryByMenuId(menuId);
            return Response.success(functionDOs);
        } catch (Exception e) {
            logger.error("API function query by menuCode error", e);
            response.setMessage(MSG.req_error_query_failed);
        }
        return response;
    }

    @Override
    public FunctionDO queryByCode(String code) {
        List<FunctionDO> functionDOList = functionDOMapper.queryByCode(code);
        if (functionDOList != null) {
            return functionDOList.get(0);
        } else {
            return null;
        }
    }

    /**
     * 获取菜单下接口
     * @param req
     * @return
     */
    @Override
    public List<FunctionInfo> underMenuFunctionList(UnderMenuFunctionListREQ req) {
        List<FunctionDO> functionDOS = functionDOMapper.selectByExample(Example.builder(FunctionDO.class).andWhere(Sqls.custom().andEqualTo("menuId", req.getMenuId())).build());
        List<FunctionInfo> functionInfos = BeanUtil.copyToList(functionDOS, FunctionInfo.class);
        return functionInfos;
    }

    @Override
    public void underMneuFunctionAdd(UnderMenuFunctionAddREQ req) {
        FunctionDO functionDO = BeanUtil.copyProperties(req, FunctionDO.class);
        functionDO.setGmtCreate(new Date())
                .setGmtModified(new Date())
                .setCreateBy(AccountUtil.getLoginInfo().getAccount());
        functionDOMapper.insert(functionDO);
    }

    @Override
    public void underMenuFunctionUpdate(UnderMenuFunctionUpdateREQ req) {
        FunctionDO functionDO = functionDOMapper.selectByPrimaryKey(req.getId());
        BeanUtil.copyProperties(req, functionDO);
        functionDO.setUpdateBy(AccountUtil.getLoginInfo().getAccount());
        functionDO.setGmtModified(new Date());
        functionDOMapper.updateByPrimaryKeySelective(functionDO);
    }

    @Override
    public void underMenuFunctionDel(UnderMenuFunctionDelREQ req) {
        functionDOMapper.deleteByPrimaryKey(req.getId());
    }

    @Override
    @Transactional
    public Response deleteFunction(Long id) {
        Response response = new Response();
        try {
            if (id == null) {
                response.setMessage(MSG.req_error_param_null, "id");
                return response;
            }
            int result = functionDOMapper.deleteByPrimaryKey(id);
            if (result == 0) {
                response.setMessage(MSG.req_error_param_invalid, "id");
                return response;
            }
            // 删除org_menu_function
            OrgMenuFunctionDO orgMenuFunctionDO = new OrgMenuFunctionDO();
            orgMenuFunctionDO.setFunctionId(id);
            orgMenuFunctionDOMapper.delete(orgMenuFunctionDO);
            // 删除role_menu_function
            RoleMenuFunctionDO roleMenuFunctionDO = new RoleMenuFunctionDO();
            roleMenuFunctionDO.setFunctionId(id);
            roleMenuFunctionDOMapper.delete(roleMenuFunctionDO);
            return response.success(null);
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            logger.error("API delete function error", e);
            response.setMessage(MSG.req_error_delete_failed);
        }
        return response;
    }

    @Override
    public Response<Map> createFunction(FunctionDO functionDO) {
        Response response = new Response();
        if (StringUtils.isBlank(functionDO.getName())) {
            response.setMessage(MSG.req_error_param_null, "name");
            return response;
        }
        if (StringUtils.isBlank(functionDO.getCode())) {
            response.setMessage(MSG.req_error_param_null, "code");
            return response;
        }
        if (functionDO.getMenuId() == null) {
            response.setMessage(MSG.req_error_param_null, "menuId");
            return response;
        }
        if (StringUtils.isBlank(functionDO.getPath())) {
            response.setMessage(MSG.req_error_param_null, "path");
            return response;
        }
        if (StringUtils.isBlank(functionDO.getMethod())) {
            response.setMessage(MSG.req_error_param_null, "method");
            return response;
        }
//        // 校验code是否已经存在
        FunctionDO query = new FunctionDO();
//        query.setCode(functionDO.getCode());
//        List<FunctionDO> functionDOS = functionDOMapper.select(query);
//        if (CollectionUtils.isNotEmpty(functionDOS)) {
//            response.setMessage(MSG.req_error_duplicate_key, "code");
//            return response;
//        }
        if (StringUtils.isNotBlank(functionDO.getPath()) && StringUtils.isNotBlank(functionDO.getMethod())) {
            query = new FunctionDO();
            query.setPath(functionDO.getPath());
            query.setMethod(functionDO.getMethod());
            List<FunctionDO> functionDOS = functionDOMapper.select(query);
            if (CollectionUtils.isNotEmpty(functionDOS)) {
                response.setMessage(MSG.req_error_record_is_exist, "path,method");
                return response;
            }
        }
        MenuDO menuDO = menuDOMapper.queryById(functionDO.getMenuId());
        if (menuDO == null || menuDO.getLevel() != MenuConstants.LEVEL_3) {
            response.setMessage(MSG.req_error_param_invalid, "menuId");
            return response;
        }
        try {
            functionDOMapper.insert(functionDO);
            return Response.success(genParamsMap("id", functionDO.getId()));
        } catch (Exception e) {
            logger.error("API create function error", e);
            if (e.getMessage().contains("uk_")) {
                return Response.error(MSG.req_error_param_code_repeat);
            }
            response.setMessage(MSG.req_error_create_failed);
        }
        return response;
    }


    @Override
    public Response<List<FunctionDO>> getFunctionList() {
        Response<List<FunctionDO>> response = new Response<List<FunctionDO>>();
        try {
            List<FunctionDO> functionDOs = functionDOMapper.selectAll();
            return response.success(functionDOs);
        } catch (Exception e) {
            logger.error("API get function list error", e);
            response.setMessage(MSG.req_error_query_failed);
        }
        return response;
    }

    @Override
    public Response updateFunction(FunctionDO functionDO) {
        Response response = new Response();
        try {
            if (functionDO.getId() == null) {
                response.setMessage(MSG.req_error_param_null, "id");
                return response;
            }
            if (functionDO.getName() != null && StringUtils.isBlank(functionDO.getName())) {
                response.setMessage(MSG.req_error_param_null, "name");
                return response;
            }
            if (functionDO.getPath() != null && StringUtils.isBlank(functionDO.getPath())) {
                response.setMessage(MSG.req_error_param_null, "path");
                return response;
            }
            if (functionDO.getMethod() != null && StringUtils.isBlank(functionDO.getMethod())) {
                response.setMessage(MSG.req_error_param_null, "method");
                return response;
            }
            // path和method 要么都传，要么都不传。
            if (StringUtils.isNotBlank(functionDO.getPath()) && StringUtils.isBlank(functionDO.getMethod())) {
                response.setMessage(MSG.req_error_param_null, "method");
                return response;
            }
            if (StringUtils.isBlank(functionDO.getPath()) && StringUtils.isNotBlank(functionDO.getMethod())) {
                response.setMessage(MSG.req_error_param_null, "path");
                return response;
            }
//            // 校验function code是否已经存在
            FunctionDO query = new FunctionDO();
//            query.setCode(functionDO.getCode());
//            List<FunctionDO> functionDOS = functionDOMapper.select(query);
//            if (CollectionUtils.isNotEmpty(functionDOS) && (functionDOS.size() > 1 || !functionDOS.get(0).getId().equals(functionDO.getId()))) {
//                response.setMessage(MSG.req_error_duplicate_key, "code");
//                return response;
//            }
            if (StringUtils.isNotBlank(functionDO.getPath()) && StringUtils.isNotBlank(functionDO.getMethod())) {
                query = new FunctionDO();
                query.setPath(functionDO.getPath());
                query.setMethod(functionDO.getMethod());
                List<FunctionDO> functionDOS = functionDOMapper.select(query);
                if (CollectionUtils.isNotEmpty(functionDOS) && (functionDO.getId() == null || functionDOS.size() > 1 || !functionDOS.get(0).getId().equals(functionDO.getId()))) {
                    response.setMessage(MSG.req_error_record_is_exist, "path,method");
                    return response;
                }
            }
            functionDO.setGmtModified(new Date());
            int result = updateNotNull(functionDO);
            if (result == 0) {
                response.setMessage(MSG.req_error_param_invalid, "id");
                return response;
            }
            return response.success(null);
        } catch (Exception e) {
            logger.error("API update function error", e);
            response.setMessage(MSG.req_error_modify_failed);
        }
        return response;
    }
}
